/*
 * Copyright (c) 2007, 2008 Johannes Krampf <Johannes.Krampf@htw-dresden.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>

#include "multiplatform.h"
#include "bstring/bstrlib.h"
#include "database.h"
#include "network.h"
#include "parser.h"
#include "general.h"

#define BUFLEN 4096

/*
 * Funktion zum Erstellen eines listen-Sockets
 */
int CreateSocket(int port) {
	int listen_sock;
	struct sockaddr_in local_addr;
	char yes = 1;

	/* Erstelle einen Socket */
	listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == listen_sock) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

    if (-1 == setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
	
	local_addr.sin_family = AF_INET;
	local_addr.sin_port = htons(port);
	local_addr.sin_addr.s_addr = INADDR_ANY;
	memset(&local_addr.sin_zero, '\0', sizeof(local_addr.sin_zero));

	/* Weise dem Socket den als Argument gegebenen Port am lokalen Rechner zu */
	if (-1 == bind(listen_sock, (struct sockaddr *)&local_addr, sizeof(local_addr))) {
		perror("bind");
		exit(EXIT_FAILURE);
	}

	/* Warte auf eingehende Verbindungen
	 * (max. 10 nicht angenommene Verbindungen werden gespeichert)
	 */
	if (-1 == listen(listen_sock, 10)) {
		perror("listen");
		exit(EXIT_FAILURE);
	}
	return listen_sock;	
}

int HTTPConnection(int http_conn) 
{ 
	int sentbytes = 0, temp = 0;
	int freemsg = 0;
	char buffer[BUFLEN];
	bstring request = NULL;
	bstring message = NULL;
	bstring bstrmsg = NULL;
	bstring tempbStr = NULL;

	if (-1 == recv(http_conn, buffer, BUFLEN-1, 0)) { 
		closesocket(http_conn);
		return -1;
	}
	buffer[BUFLEN-1] = '\0';
	
	tempbStr = cstr2bstr(buffer);
	request = ParseRequest(tempbStr);
	bdestroy(tempbStr);
	tempbStr = NULL;

	if (NULL == request) {
		bstrmsg = GetFileContent("500.htm");
		if (NULL == bstrmsg) {
			tempbStr = cstr2bstr("Datenbankfehler: Fehlerseite 500 - interner Serverfehler nicht gefunden!\n");
			message = HTTPMessage(500, "text/html", tempbStr);
			bdestroy(tempbStr);
		}else {
			message = HTTPMessage(500, "text/html", bstrmsg);
		}
	}else {
		printf("%s\n", (char *)request->data);
		bstrmsg = DynamicRequest((char *)request->data);
		if (NULL == bstrmsg) {
			bstrmsg = GetFileContent((char *)request->data);
		}else {
			freemsg = 1;
		}
		if (NULL == bstrmsg) {
			bstrmsg = GetFileContent("404.htm");
			if (NULL == bstrmsg) {
				message = HTTPMessage(404, "text/html", cstr2bstr("Datenbankfehler: Fehlerseite 404 - Datei nicht gefunden nicht gefunden!\n"));
			}else {
				message = HTTPMessage(404, "text/html", bstrmsg);
			}
		}else {
			message = HTTPMessage(200, GetMimeType((char *)request->data), bstrmsg);
		}
	}

	if (1 == freemsg) {
		bdestroy(bstrmsg);
	}

    while(sentbytes < message->slen) {
        temp = send(http_conn, (char *)message->data+sentbytes, message->slen-sentbytes, 0);
		if (-1 == temp) {
			perror("send");
			break;
		}
		sentbytes += temp;
	}

	closesocket(http_conn);

	bdestroy(request);
	bdestroy(message);
	
	return 0;
}

bstring HTTPMessage(int status, char* mimetype, bstring message) {
	bstring temp = NULL;
	bstring http_msg = cstr2bstr("");;
	
	if (200 == status) {
		bcatcstr(http_msg, "HTTP/1.0 200 OK\r\n");
	}else if (404 == status) {
		bcatcstr(http_msg, "HTTP/1.0 404 Not Found\r\n");
	}else {
		bcatcstr(http_msg, "HTTP/1.0 500 internal error\r\n");
	}
	
	bcatcstr(http_msg, "Server: verbconf\r\n");
	bcatcstr(http_msg, "Content-Type: ");
	bcatcstr(http_msg, mimetype);
	bcatcstr(http_msg, "\r\nContent-Length: ");
	temp = bformat("%d", message->slen);
	bconcat(http_msg, temp);
	bcatcstr(http_msg, "\r\n\r\n");
	bconcat(http_msg, message);

	bdestroy(temp);
	temp = NULL;

	return http_msg;
}
